package com.spring.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import java.io.*;
import java.util.Date;
import java.util.Map;
import java.util.function.Function;
import javax.crypto.SecretKey;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * jwt工具类,将数据（令牌）进行加密和解密操作
 * @author tanwubo
 */
@Component
public class JwtTokenUtils {

    private Long expiration = 259200L; // 过期时间，默认为259200秒（3天）

    public SecretKey key; // 密钥

    /**
     * JwtTokenUtils 类的构造函数，用于初始化密钥
     */
    public JwtTokenUtils() {
        key = (SecretKey) readObj(); // 从文件中读取密钥
        if (key == null) {
            key = Keys.secretKeyFor(SignatureAlgorithm.HS256); // 生成新的密钥
            writeObj(key); // 将密钥写入文件
        }
    }

    /**
     * 将对象序列化并写入文件
     *
     * @param p 要写入的对象//@param 是一个用于方法注释的标签，用于描述方法的参数。
     */
    /**
     * 将对象写入文件
     * @param p 要写入的对象
     */
    public static void writeObj(Object p) {
        try {
            // 创建文件对象
            File file = new File("JwtTokenUtils.txt");//创建文件对象，指定要写入的文件路径
            // 创建ObjectOutputStream对象，并传入文件输出流
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file));//写入文件

            // 将对象写入输出流
            objectOutputStream.writeObject(p);

            // 关闭输出流
            objectOutputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 从文件中反序列化对象
     *
     * @return 反序列化得到的对象
     */
    /**
     * 从文件中读取对象
     * @return 读取到的对象，如果读取失败则返回null
     */
    public static Object readObj() {
        Object p = null;
        try {
            // 创建文件对象
            File file = new File("JwtTokenUtils.txt");//创建文件对象，指定要读取的文件路径
            // 创建ObjectInputStream对象，并传入文件输入流
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file));//用于读取对象
            try {
                // 读取对象
                p = objectInputStream.readObject();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return p;
    }

    /**
     * 从令牌中获取用户ID
     *
     * @param token 令牌
     * @return 用户ID
     */
    public String getUserIdFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    /**
     * 从令牌中获取指定声明的值
     *
     * @param token           令牌
     * @param claimsResolver  声明解析器
     * @param <T>             声明的类型
     * @return 声明的值
     */
    public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }

    /**
     * 从令牌中获取所有声明
     *
     * @param token 令牌
     * @return 所有声明
     */
    private Claims getAllClaimsFromToken(String token) {
        return Jwts.parser().setSigningKey(this.key).parseClaimsJws(token).getBody();
    }

    /**
     * 生成令牌
     *
     * @param userId 用户ID
     * @param claims 声明
     * @return 生成的令牌
     */
    public String generateToken(Object userId, Map<String, Object> claims) {
        return doGenerateToken(claims, String.valueOf(userId));
    }

    /**
     * 实际生成令牌的方法
     *
     * @param claims  声明
     * @param subject 主题
     * @return 生成的令牌
     */
    private String doGenerateToken(Map<String, Object> claims, String subject) {
        final Date createdDate = new Date();
        final Date expirationDate = calculateExpirationDate(createdDate);

        return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(createdDate).setExpiration(expirationDate).signWith(this.key).compact();
    }

    /**
     * 计算令牌过期时间
     *
     * @param createdDate 令牌创建时间
     * @return 过期时间
     */
    private Date calculateExpirationDate(Date createdDate) {
        return new Date(createdDate.getTime() + expiration * 1000);
    }
}
